/**
 * 
 */
package cn.dgfy.MyBatisStudy.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * @author Tearfalls
 *
 */
public class DbUtil {
	
	// 用于缓存已经生成的SqlSessionFactory对象，以便在使用相同配置文件的时候无需反复生成SqlSessionFactory对象
	private static SqlSessionFactory factory = null;
	
	// 用于缓存生成当前SqlSessionFactory对象时使用的配置文件名，如果再次收到生成SqlSessionFactory对象的请求时，如果请求指定的配置文
	// 件文件名与此处缓存的文件名相同，则不再次生成SqlSessionFactory对象，则是直接返回已缓存的SqlSessionFactory对象，如果接收到的配
	// 置文件文件名与生成当前已缓存SqlSessionFactory对象时所使用的配置文件不同名，则以指定的配置文件重新生成SQLSessionFactory对象并
	// 将其缓存
	private static String configResource = null;
	
	static {
		try {
			getSqlSessionFactory();
		} catch (IOException e) {
			e.getMessage();
		}
	}
	
	/**
	 * 使用指定的全局配置文件生成SqlSessionFactory。生成的SqlSessionFactory会被缓存，如果指定的全局配置文件名与上次使用的文件名相
	 * 同，则不再重复生成SqlSessionFactory，而是直接返回已缓存的SqlSessionFactory
	 * @param resource 用于生成SqlSessionFactory的全局配置文件的文件名（含路径）
	 * @return 由指定的全局配置文件生成的SqlSessionFactory
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSessionFactory getSqlSessionFactory(String resource) throws IOException {
		if (factory == null || !resource.equals(configResource)) {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			factory = new SqlSessionFactoryBuilder().build(inputStream);
			configResource = resource;
		}
		
		return factory;
	}
	
	/**
	 * 使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory。生成的SqlSessionFactory会被缓存（但可能被由其他配置文件生
	 * 成的SqlSessionFactory覆盖）。如果现有被缓存的SqlSessionFactory也是由配置文件mybatis-config-test.xml生成的，则不再重复生
	 * 成SqlSessionFactory，而是直接返回已缓存的SqlSessionFactory
	 * @return 由指定的全局配置文件生成的SqlSessionFactory
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSessionFactory getSqlSessionFactory() throws IOException {
		return getSqlSessionFactory("mybatis-config-test.xml");
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * 生成的SqlSession对象使用的Executor类型由全局配置文件中的defaultExecutorType选项指定，如无此选项则使用SimpleExecutor
	 * @param autoCommit 指明生成的SqlSession对象是否自动提交事务
	 * @return 生成的SqlSession对象
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getSqlSession(boolean autoCommit) throws IOException {
		if (factory == null) {
			getSqlSessionFactory();
		}
		
		return factory.openSession(autoCommit);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个不自动提交的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * 生成的SqlSession对象使用的Executor类型由全局配置文件中的defaultExecutorType选项指定，如无此选项则使用SimpleExecutor
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getSqlSession() throws IOException {
		return getSqlSession(false);
	}
	
	private static SqlSession getSqlSession(ExecutorType execType, boolean autoCommit) throws IOException {
		if (factory == null) {
			getSqlSessionFactory();
		}
		
		return factory.openSession(execType, autoCommit);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用SimpleExecutor的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @param autoCommit 指明生成的SqlSession对象是否自动提交事务
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getSimpleSqlSession(boolean autoCommit) throws IOException {
		return getSqlSession(ExecutorType.SIMPLE, autoCommit);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用SimpleExecutor的自动提交事务的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getSimpleAutoCommitSqlSession() throws IOException {
		return getSimpleSqlSession(true);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用SimpleExecutor的不自动提交事务的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getSimpleNonAutoCommitSqlSession() throws IOException {
		return getSimpleSqlSession(false);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用BatchExecutor的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @param autoCommit 指明生成的SqlSession对象是否自动提交事务
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getBatchSqlSession(boolean autoCommit) throws IOException {
		return getSqlSession(ExecutorType.BATCH, autoCommit);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用BatchExecutor的自动提交事务的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getBatchAutoCommitSqlSession() throws IOException {
		return getBatchSqlSession(true);
	}
	
	/**
	 * 使用当前缓存的SqlSessionFactory生成一个使用BatchExecutor的不自动提交事务的SqlSession对象
	 * 如果没有已缓存的SqlSessionFactory，则使用全局配置文件mybatis-config-test.xml生成SqlSessionFactory，而后再生成SqlSession
	 * @return 生成的SqlSession
	 * @throws IOException 如果全局配置文件不存在或无法读取则抛出此异常
	 */
	public static SqlSession getBatchNonAutoCommitSqlSession() throws IOException {
		return getBatchSqlSession(false);
	}
}
